package cn.south.campus.business.service.impl;

import cn.south.campus.business.mapper.ComplaintMapper;
import cn.south.campus.business.model.bo.LoginContext;
import cn.south.campus.business.model.entity.Complaint;
import cn.south.campus.business.model.enums.CampusErrorEnums;
import cn.south.campus.business.model.enums.ComplaintEnums;
import cn.south.campus.business.model.req.ComplaintReq;
import cn.south.campus.business.model.vo.ComplaintVo;
import cn.south.campus.business.service.CommentService;
import cn.south.campus.business.service.ComplaintCountService;
import cn.south.campus.business.service.ComplaintService;
import cn.south.campus.common.exceptions.BusinessException;
import cn.south.campus.common.model.enums.CommonEnums;
import cn.south.campus.common.utils.AssertUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 校园吐槽表 服务实现类
 * </p>
 *
 * @author chow
 * @since 2024-12-05
 */
@Service
@AllArgsConstructor
public class ComplaintServiceImpl extends ServiceImpl<ComplaintMapper, Complaint> implements ComplaintService {

    private final ComplaintMapper complaintMapper;

    private final ComplaintCountService complaintCountService;

    private final CommentService commentService;

    @Override
    public IPage<ComplaintVo> pageQuery(ComplaintReq query) {
        query.setStatus(ComplaintEnums.PUBLISH.getCode());
        PageDTO<Complaint> complaintPageDTO = complaintMapper.pageQuery(query.getPageDto(), query);
        List<Long> complaintIds = complaintPageDTO.getRecords().stream().map(Complaint::getId).collect(Collectors.toList());
        Map<Long, boolean[]> res = complaintCountService.selectMeOpt(complaintIds, ComplaintEnums.BizType.COMPLAINT.getCode());
        Map<Long, Map<Integer, Long>> cntMap = complaintCountService.selectCount(complaintIds, ComplaintEnums.BizType.COMPLAINT.getCode());
        Map<Long, Long> commentCntMap = commentService.selectCount(complaintIds);
        return complaintPageDTO.convert(item -> {
            ComplaintVo complaintVo = ComplaintVo.convert(item);
            if (!CollectionUtils.isEmpty(res) && res.get(item.getId()) != null) {
                complaintVo.setAgree(res.get(item.getId())[0]);
                complaintVo.setReject(res.get(item.getId())[1]);
            }
            if (!CollectionUtils.isEmpty(commentCntMap)) {
                complaintVo.setCommentCount(commentCntMap.getOrDefault(item.getId(), 0L));
            }
            if (!CollectionUtils.isEmpty(cntMap) && !CollectionUtils.isEmpty(cntMap.get(item.getId()))) {
                Map<Integer, Long> longMap = cntMap.get(item.getId());
                complaintVo.setAgreeCount(longMap.getOrDefault(ComplaintEnums.CountType.LIKE.getCode(), 0L));
                complaintVo.setRejectCount(longMap.getOrDefault(ComplaintEnums.CountType.DISLIKE.getCode(), 0L));
            }
            return complaintVo;
        });
    }

    @Override
    public IPage<ComplaintVo> pageQueryMe(ComplaintReq query) {
        Long userId = LoginContext.getContext().getId();
        query.setUserId(userId);
        PageDTO<Complaint> complaintPageDTO = complaintMapper.pageQuery(query.getPageDto(), query);
        List<Long> complaintIds = complaintPageDTO.getRecords().stream().map(Complaint::getId).collect(Collectors.toList());
        Map<Long, boolean[]> res = complaintCountService.selectMeOpt(complaintIds, ComplaintEnums.BizType.COMPLAINT.getCode());
        Map<Long, Map<Integer, Long>> cntMap = complaintCountService.selectCount(complaintIds, ComplaintEnums.BizType.COMPLAINT.getCode());
        Map<Long, Long> commentCntMap = commentService.selectCount(complaintIds);
        return complaintPageDTO.convert(item -> {
            ComplaintVo complaintVo = ComplaintVo.convert(item);
            if (!CollectionUtils.isEmpty(res) && res.get(item.getId()) != null) {
                complaintVo.setAgree(res.get(item.getId())[0]);
                complaintVo.setReject(res.get(item.getId())[1]);
            }
            if (!CollectionUtils.isEmpty(commentCntMap)) {
                complaintVo.setCommentCount(commentCntMap.getOrDefault(item.getId(), 0L));
            }
            if (!CollectionUtils.isEmpty(cntMap) && !CollectionUtils.isEmpty(cntMap.get(item.getId()))) {
                Map<Integer, Long> longMap = cntMap.get(item.getId());
                complaintVo.setAgreeCount(longMap.getOrDefault(ComplaintEnums.CountType.LIKE.getCode(), 0L));
                complaintVo.setRejectCount(longMap.getOrDefault(ComplaintEnums.CountType.DISLIKE.getCode(), 0L));
            }
            return complaintVo;
        });
    }

    @Override
    public ComplaintVo detail(Long id) {
        Complaint complaint = complaintMapper.detail(id, ComplaintEnums.PUBLISH.getCode());
        ComplaintVo complaintVo = ComplaintVo.convert(complaint);
        Map<Integer, Long> longMap = complaintCountService.selectCount(complaintVo.getId(), ComplaintEnums.BizType.COMPLAINT.getCode());
        boolean[] booleans = complaintCountService.selectMeOpt(complaintVo.getId(), ComplaintEnums.BizType.COMPLAINT.getCode());
        complaintVo.setAgree(booleans[0]);
        complaintVo.setReject(booleans[1]);
        if (!CollectionUtils.isEmpty(longMap)) {
            complaintVo.setAgreeCount(longMap.getOrDefault(ComplaintEnums.CountType.LIKE.getCode(), 0L));
            complaintVo.setRejectCount(longMap.getOrDefault(ComplaintEnums.CountType.DISLIKE.getCode(), 0L));
        }
        return complaintVo;
    }

    @Override
    public ComplaintVo detailMe(Long id) {
        Long userId = LoginContext.getContext().getId();
        Complaint complaint = complaintMapper.selectById(id);
        if (!complaint.getUserId().equals(userId)) {
            return null;
        }
        ComplaintVo complaintVo = ComplaintVo.convert(complaint);
        Map<Integer, Long> longMap = complaintCountService.selectCount(complaintVo.getId(), ComplaintEnums.BizType.COMPLAINT.getCode());
        if (!CollectionUtils.isEmpty(longMap)) {
            complaintVo.setAgreeCount(longMap.getOrDefault(ComplaintEnums.CountType.LIKE.getCode(), 0L));
            complaintVo.setRejectCount(longMap.getOrDefault(ComplaintEnums.CountType.DISLIKE.getCode(), 0L));
        }
        return complaintVo;
    }

    @Override
    public void deleteComplaint(Long id) {
        Long userId = LoginContext.getContext().getId();
        Complaint complaint = complaintMapper.selectById(id);
        AssertUtils.isNotNull(complaint, CommonEnums.DATA_HAS_NOT_ERROR);
        if (complaint.getUserId().equals(userId)) {
            complaintMapper.deleteById(id);
        }
    }

    @Override
    public void updateComplaint(ComplaintVo complaintVo) {
        Long userId = LoginContext.getContext().getId();
        Complaint complaint = complaintMapper.selectById(complaintVo.getId());
        if (complaint.getUserId().equals(userId)) {
            complaintMapper.updateById(ComplaintVo.convert(complaintVo));
        }
    }

    @Override
    public void addComplaint(ComplaintVo complaint) {
        Complaint convert = ComplaintVo.convert(complaint);
        convert.setUserId(LoginContext.getContext().getId());
        convert.setStatus(ComplaintEnums.PUBLISH.getCode());
        convert.setPublishTime(LocalDateTime.now());
        complaintMapper.insert(convert);
    }

    @Override
    public void updateStatusComplaint(Long id, Integer status) {
        Long userId = LoginContext.getContext().getId();
        Complaint complaint = complaintMapper.selectById(id);
        if (complaint.getUserId().equals(userId)) {
            complaint.setStatus(status);
            complaint.setPublishTime(LocalDateTime.now());
            complaintMapper.updateById(complaint);
        }
    }

    @Override
    public void agreeComplaint(Long id) {
        Long userId = LoginContext.getContext().getId();
        LambdaQueryWrapper<Complaint> wrapper = new LambdaQueryWrapper<Complaint>()
                .eq(Complaint::getId, id)
                .eq(Complaint::getStatus, ComplaintEnums.PUBLISH.getCode());
        Complaint complaint = complaintMapper.selectOne(wrapper);
        if (complaint.getUserId().equals(userId)) {
            throw new BusinessException(CampusErrorEnums.COMPLAINT_NOT_AGREE_SELF);
        }
        complaintCountService.cntSave(id, ComplaintEnums.CountType.LIKE.getCode(), ComplaintEnums.BizType.COMPLAINT.getCode());
    }

    @Override
    public void rejectComplaint(Long id) {
        Long userId = LoginContext.getContext().getId();
        LambdaQueryWrapper<Complaint> wrapper = new LambdaQueryWrapper<Complaint>()
                .eq(Complaint::getId, id)
                .eq(Complaint::getStatus, ComplaintEnums.PUBLISH.getCode());
        Complaint complaint = complaintMapper.selectOne(wrapper);
        if (complaint.getUserId().equals(userId)) {
            throw new BusinessException(CampusErrorEnums.COMPLAINT_NOT_REJECT_SELF);
        }
        complaintCountService.cntSave(id, ComplaintEnums.CountType.DISLIKE.getCode(), ComplaintEnums.BizType.COMPLAINT.getCode());
    }

    @Override
    public IPage<ComplaintVo> pageMyOpt(ComplaintReq query) {
        Long userId = LoginContext.getContext().getId();
        query.setUserId(userId);
        PageDTO<Complaint> complaintPageDTO = complaintMapper.pageQueryMyOpt(query.getPageDto(), query);
        if (CollectionUtils.isEmpty(complaintPageDTO.getRecords())) {
            return complaintPageDTO.convert(ComplaintVo::convert);
        }
        List<Long> complaintIds = complaintPageDTO.getRecords().stream().map(Complaint::getId).collect(Collectors.toList());
        Map<Long, boolean[]> res = complaintCountService.selectMeOpt(complaintIds, ComplaintEnums.BizType.COMPLAINT.getCode());
        Map<Long, Map<Integer, Long>> cntMap = complaintCountService.selectCount(complaintIds, ComplaintEnums.BizType.COMPLAINT.getCode());
        Map<Long, Long> commentCntMap = commentService.selectCount(complaintIds);
        return complaintPageDTO.convert(item -> {
            ComplaintVo complaintVo = ComplaintVo.convert(item);
            if (!CollectionUtils.isEmpty(res) && res.get(item.getId()) != null) {
                complaintVo.setAgree(res.get(item.getId())[0]);
                complaintVo.setReject(res.get(item.getId())[1]);
            }
            if (!CollectionUtils.isEmpty(commentCntMap)) {
                complaintVo.setCommentCount(commentCntMap.getOrDefault(item.getId(), 0L));
            }
            if (!CollectionUtils.isEmpty(cntMap) && !CollectionUtils.isEmpty(cntMap.get(item.getId()))) {
                Map<Integer, Long> longMap = cntMap.get(item.getId());
                complaintVo.setAgreeCount(longMap.getOrDefault(ComplaintEnums.CountType.LIKE.getCode(), 0L));
                complaintVo.setRejectCount(longMap.getOrDefault(ComplaintEnums.CountType.DISLIKE.getCode(), 0L));
            }
            return complaintVo;
        });
    }
}
